package com.uxsino.commons.logicSelector;

import java.io.IOException;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.uxsino.commons.utils.config.PropElement;
import com.uxsino.commons.utils.config.PropJsonDocument;
import com.uxsino.commons.utils.config.PropXMLDocument;
import com.uxsino.commons.utils.debug.SourceInfo;

public class SelectorFactory<ObjectType> {
    private static Logger logger = LoggerFactory.getLogger(SelectorFactory.class);

    public ISelector<ObjectType> createSelector(String name) {
        switch (name) {
        case "prop":
            return new PropSelector<ObjectType>();
        case "ref":
            return new RefSelector<ObjectType>();
        case "selector":
            return new SelectorGroup<ObjectType>();

        }
        return null;
    }

    public ISelector<ObjectType> createSelector(PropElement eSelector) {

        AbstractSelector<ObjectType> selector = null;

        switch (eSelector.getTagName("type")) {
        case "prop":
            selector = createPropSelector(eSelector.getProp("name"), eSelector.getProp("op"),
                eSelector.getProp("value"));
            break;
        case "ref":
            selector = new RefSelector<ObjectType>(eSelector.getProp("name"));
            break;
        case "selector":
            selector = createSelectorGroup(GROUPBY_TYPE.fromName(eSelector.getProp("group-by")),
                eSelector);
            break;
        default:
            selector = createSelectorGroup(GROUPBY_TYPE.fromName(eSelector.getTagName()), eSelector);
            break;
        }

        if (selector != null) {
            SourceInfo info = new SourceInfo();
            info.source = (String) eSelector.getSourceName();
            info.location = (String) eSelector.getSourceLocation();
            if (info.source != null) {
                selector.setSourceInfo(info);
            }
        }
        return selector;
    }

    public SelectorGroup<ObjectType> createSelectorGroup(PropElement egroup) {
        return createSelectorGroup(GROUPBY_TYPE.fromName(egroup.getProp("group-by")), egroup);
    }

    public SelectorGroup<ObjectType> createSelectorGroup(GROUPBY_TYPE groupby, PropElement egroup) {
        SelectorGroup<ObjectType> selectorGroup = new SelectorGroup<ObjectType>(groupby);

        if (egroup == null) {
            return selectorGroup;
        }
        List<PropElement> nl = egroup.getChildElements("selectors");
        for (int i = 0; i < nl.size(); i++) {
            PropElement node = nl.get(i);

            try {
                ISelector<ObjectType> sel = createSelector(node);
                selectorGroup.add(sel);
            } catch (IllegalArgumentException e) {
                logger.error(
                    "error creating selector:, " + egroup.getSourceName() + "[" + egroup.getSourceLocation() + "]", e);
            }
        }

        return selectorGroup;
    }

    public SelectorGroup<ObjectType> createSelectorGroupFromXMLString(String xml, String sourceName) {
        PropXMLDocument doc = new PropXMLDocument(xml, sourceName, PropXMLDocument.SOURCE_TYPE.STRING);
        return createSelectorGroup(doc.getRootElement());
    }

    public SelectorGroup<ObjectType> createSelectorGroupFromJsonString(String json, String sourceName)
        throws JsonProcessingException, IOException {
        JsonNode j = (new ObjectMapper()).readTree(json);
        PropJsonDocument doc = new PropJsonDocument(j);
        return createSelectorGroup(doc.getRootElement());
    }

    public PropSelector<ObjectType> createPropSelector(String propName, String operatorName, String value) {
        return new PropSelector<ObjectType>(propName, operatorName, value);
    }

}
